/*
 * ThreadMain.cpp
 *
 *  Created on: 2017年5月28日
 *      Author: orange
 */

#include "ThreadMain.h"

#include <iostream>
#include <sstream>

#include "../public/event/OnCommandJuzEvent.h"
#include "../public/event/OnDisableJuzEvent.h"
#include "../public/event/OnEnableJuzEvent.h"
#include "../public/event/ThreadJuzEvent.h"

#include "../public/PublicDefine.h"
ThreadMain* ThreadMain::mThreadMain = NULL;

#define MAXTHREAD 150
int ThreadMain::nMaxCount = MAXTHREAD;//最大线程数
int ThreadMain::nMinCount = 20;//最小线程数
int ThreadMain::nCounter = 10;//计数器

static pthread_t *ths[MAXTHREAD] = {NULL};

Plugin *loadSoPlugin()
{
	Plugin *pl =  ThreadMain::getInstance();
	return pl;
}

ThreadMain* ThreadMain::getInstance() {
	if(mThreadMain == NULL)
	{
		mThreadMain = new ThreadMain();
	}
	return mThreadMain;
}
void* ThreadMain::TaskPro(void *)
{
	while(1)
	{
		sem_wait(ThreadMain::getInstance()->bin_sem);
		Juz_Task_Ve JuzTv;

		if(ThreadMain::getInstance()->TaskQueue.try_dequeue(JuzTv))
		{
			ThreadMain::getInstance()->Log("线程任务:" + JuzTv.msg,4);
			JuzTv.mTask(JuzTv.Args);
			ThreadMain::getInstance()->Log("线程任务结束:" + JuzTv.msg);
		}
		ThreadMain::getInstance()->quit();
	}
	return NULL;
}

void ThreadMain::access()
{
	pthread_mutex_lock(mMutex);
	nCurrentWorkCOunt++;
	pthread_mutex_unlock(mMutex);
}
void ThreadMain::quit()
{
	pthread_mutex_lock(mMutex);
	nCurrentWorkCOunt--;
	pthread_mutex_unlock(mMutex);
}

ThreadMain::ThreadMain() {
	JuzLog::Init(this);

	cout<<"new ThreadMain"<<endl;
	nCurrentCount = 0;
	nCurrentWorkCOunt = 0;

	mMutex = new pthread_mutex_t;
	pthread_mutex_init(mMutex, NULL);

	bin_sem = new sem_t;
	sem_init(bin_sem, 0, 0);
}

ThreadMain::~ThreadMain() {
	OnDisable();
}

//检查线程
void ThreadMain::CheckThread(int count)
{
	int nLickTo = nCounter / 2;
	if((nCurrentWorkCOunt + nLickTo) >= nCurrentCount)
	{
		if(pthread_mutex_lock(mMutex) == 0)//成功加锁
		{
			if((nCurrentWorkCOunt + nLickTo) >= nCurrentCount)
			{
				StartThread(nCounter);
			}
			pthread_mutex_unlock(mMutex);//要解锁
		}
	}

}
void ThreadMain::OnEnable()
{
	Log("ThreadMain 初始化线程！");
	StartThread(nMinCount);
	Log("ThreadMain 初始化线程！结束");
}

void ThreadMain::eventListen(JuzEvent* event) {
	string evName = event->mEventName;
	if(evName == OnEnableJuzEvent::mEventName)
	{
		OnEnable();
	}
	else if(evName == ThreadJuzEvent::mEventName)
	{
		ThreadJuzEvent *ev = (ThreadJuzEvent*)event;
		Juz_Task_Ve JuzTv;
		JuzTv.mTask = ev->getTask();
		JuzTv.Args = ev->getArgs();
		JuzTv.msg = ev->getMsg();

		CheckThread();
		if(TaskQueue.enqueue(JuzTv))
		{
			ThreadMain::getInstance()->access();
			sem_post(bin_sem); //增加信号量
		}
	}
	else if(evName == OnDisableJuzEvent::mEventName)
	{
		OnDisable();
	}
	else if(evName == OnCommandJuzEvent::mEventName)
	{
		OnCommand((OnCommandJuzEvent*)event);
	}
}

void ThreadMain::bindFinsh() {
	registeredEvent(OnEnableJuzEvent::mEventName,15);
	registeredEvent(ThreadJuzEvent::mEventName,15);
	registeredEvent(OnDisableJuzEvent::mEventName,20);
	registeredEvent(OnCommandJuzEvent::mEventName,1);
}

void ThreadMain::StartThread(int num) {
	if(nCurrentCount >= nMaxCount) return;

	int nLickTO = nCurrentCount + num;
	int nCount = num;

	if(nLickTO >= nMaxCount)
	{
		nCount = nLickTO - nMaxCount;
	}
	static int currentItea = 0;
	for(int i = 0; i < nCount ; i++)
	{
		int ret = -1;
		pthread_t *th = new pthread_t;
		ths[currentItea] = th;

		ret = pthread_create( th, NULL, ThreadMain::TaskPro, NULL);
		if(ret == 0)
		{
			nCurrentCount++;
			currentItea ++;
		}
	}
}



void ThreadMain::OnDisable() {

	pthread_mutex_destroy(mMutex);
	sem_destroy(bin_sem);

	Log("开始销毁线程!");
	for(int i = 0 ; i < nMaxCount ; i++)
	{
		if(ths[i] != NULL)
		{
			pthread_cancel(*ths[i]);
		}
	}

}

void ThreadMain::OnCommand(OnCommandJuzEvent* ev) {
	int nLen = ev->getLen();
	if(nLen == 2)
	{
		string strCommand = ev->getCommand(0);
		if(strCommand == "thread")
		{
			strCommand =  ev->getCommand(1);
			if(strCommand == "info")
			{
				cout << "当前线程总数:"<<nCurrentCount<<" 当前工作中的线程:"<<nCurrentWorkCOunt<<endl;
			}
		}
	}

}

void ThreadMain::Log(string msg, int nPriority) {
	JuzLog::LogStr(msg.c_str(),nPriority);
}
